package com.mikufufu.blog.aop;


import com.alibaba.fastjson2.JSON;
import com.mikufufu.blog.common.constant.HttpStatus;
import com.mikufufu.blog.common.entity.AjaxResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

@Slf4j
@Aspect
@Component
@Order(1) // 数值越小优先级越高
public class WebAspect {

    @Autowired
    private MessageSource messageSource;

    @Pointcut("execution(* com.mikufufu.blog.controller..*.*(..))")
    public void controllerLog() {
    }

    @Around("controllerLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request = getRequest();
        if (request == null){
            return point.proceed();
        }
        // 获取方法签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        String url =  request.getRequestURI();
        log.debug("请求{} :{}", request.getMethod(),url);
        try {
            // 获取参数类型数组（Class类型）
            Class<?>[] paramTypes = signature.getParameterTypes();
            // 获取参数值数组
            Object[] args = point.getArgs();
            String[] paramNames = signature.getParameterNames();
            for (int i = 0; i < args.length; i++) {
                // 如果是MultipartFile类型，则打印文件名
                if (args[i] instanceof MultipartFile) {
                    MultipartFile file = (MultipartFile) args[i];
                    log.debug("上传文件 ({}){} 文件名{}", paramTypes[i].getSimpleName(), paramNames[i], file.getOriginalFilename());
                    continue;
                }
                // 忽略HttpServletRequest和HttpServletResponse
                if (args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse) {
                    continue;
                }
                // 忽略null和byte[]
                if (args[i] == null || args[i] instanceof byte[]) {
                    log.debug("入参值为空或者是字节流 ({}){}", paramTypes[i].getSimpleName(), paramNames[i]);
                    continue;
                }
                log.debug("入参 ({}){}：{}", paramTypes[i].getSimpleName(), paramNames[i], JSON.toJSONString(args[i]));
            }
        } catch (Exception e) {
            log.error("接口{}入参解析失败", url, e);
        }
        long startTime = System.currentTimeMillis();
        Object result = point.proceed();
        long endTime = System.currentTimeMillis();
        try {
            if (result instanceof AjaxResult) {
                AjaxResult<?> ajaxResult = (AjaxResult<?>) result;
                translate(ajaxResult,LocaleContextHolder.getLocale());
                if (ajaxResult.getData() != null) {
                    log.debug("通用接口{}出参({})：{}", url,ajaxResult.dataType().getSimpleName(), JSON.toJSONString(ajaxResult));
                }
                if (ajaxResult.getCode() == HttpStatus.SUCCESS) {
                    log.debug("接口{}执行成功", url);
                } else {
                    log.debug("接口{}执行失败，返回码{}，返回信息{}", url, ajaxResult.getCode(), ajaxResult.getMsg());
                }
            }
        } catch (Exception e) {
            log.error("接口{}出参解析失败", url, e);
        }
        log.debug("接口{}执行结束，耗时{}ms", url, endTime - startTime);
        return result;
    }

    private HttpServletRequest getRequest() {
        // 从当前请求中获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            return ((ServletRequestAttributes) requestAttributes).getRequest();
        }
        return null;
    }

    /**
     * 翻译国际化
     * @param ajaxResult {@link AjaxResult}
     */
    private void translate(AjaxResult<?> ajaxResult,Locale locale){
        String key = ajaxResult.getMsg();
        String msg = messageSource.getMessage(key, null, locale);
        log.info("SpringBoot的MessageSource国际化{}测试： {}:{}", locale, key, msg);
        ajaxResult.setMsg(msg);
    }
}
